﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Media;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace TouchControls
{
    [
     TemplateVisualState(GroupName = "SelectionStates", Name = "Children"),
     TemplateVisualState(GroupName = "SelectionStates", Name = "Active"),
     TemplateVisualState(GroupName = "SelectionStates", Name = "HoveredParent"),
     TemplateVisualState(GroupName = "SelectionStates", Name = "Hovered"),
     TemplateVisualState(GroupName = "SelectionStates", Name = "Inactive"),
    TemplateVisualState(GroupName = "SelectionStates", Name = "InactiveParent"),
     TemplateVisualState(GroupName = "ExpansionStates", Name = "Expanded"),
     TemplateVisualState(GroupName = "ExpansionStates", Name = "Collapsed"),
     TemplateVisualState(GroupName = "HasItemsStates", Name = "HasItems"),
     TemplateVisualState(GroupName = "HasItemsStates", Name = "NoItems")]
    [TemplatePart(Name = "ItemButton", Type = typeof(FrameworkElement))]
    [TemplatePart(Name = "ItemsHost", Type = typeof(FrameworkElement))]
    public partial class TouchMenuItem : ItemsControl
    {
        protected enum SelectionStates
        {
            Children,
            Active,
            HoveredParent,
            Hovered,
            Inactive,
            InactiveParent
        }

        internal Rect ButtonRect { get; set; }

        public event RoutedEventHandler Click;

        internal Canvas MenuContainer { get; set; }
        internal Canvas LineCanvas { get; set; }
        internal TouchMenuContainer ItemContainer { get; set; }

        static TouchMenuItem()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(TouchMenuItem), new FrameworkPropertyMetadata(typeof(TouchMenuItem)));
        }

        public TouchMenuItem()
        {
            HasItems = false;
        }

        public Button ItemButton { get; private set; }

        #region overrides
        protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            base.OnItemsChanged(e);
            this.HasItems = this.Items.Count > 0;            
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            ItemContainer = this.FindParent<TouchMenuContainer>();
            var adornment = AdornmentGrid.For(this);
            ItemButton = this.GetTemplateChild("ItemButton") as Button;
            LineCanvas = this.GetTemplateChild("LineCanvas") as Canvas;
            MenuContainer = this.GetTemplateChild("MenuContainer") as Canvas;
            MenuContainer.Width = adornment.RenderSize.Width;
            MenuContainer.Height = adornment.RenderSize.Height;
            LineCanvas.Width = adornment.RenderSize.Width;
            LineCanvas.Height = adornment.RenderSize.Height;  
            ItemButton.Click += new RoutedEventHandler(ItemButtonClick);

            ItemButton.AddHandler(UIElement.TouchUpEvent, new EventHandler<TouchEventArgs>(TouchUp), true);
            ItemButton.AddHandler(UIElement.TouchDownEvent, new EventHandler<TouchEventArgs>(TouchDown));
            ItemButton.AddHandler(UIElement.TouchMoveEvent, new EventHandler<TouchEventArgs>(TouchMove), true);

            ItemButton.AddHandler(UIElement.MouseMoveEvent, new MouseEventHandler(ItemButton_MouseMove), true);
            ItemButton.AddHandler(UIElement.MouseDownEvent, new MouseButtonEventHandler(ItemButton_MouseDown));
            ItemButton.AddHandler(UIElement.MouseUpEvent, new MouseButtonEventHandler(ItemButton_MouseUp), true);
            var icon = ItemButton.FindDescendants(obj => obj is Image).FirstOrDefault();
            ParentMenu = this.FindParent<TouchMenuItem>();
            CheckHostVisibility();
            //_btn.MouseLeftButtonDown += new MouseButtonEventHandler(ExpandMenu);
        }

        void TouchDown(object sender, TouchEventArgs e)
        {
            if (ItemContainer != null)
            {
                ItemContainer.DelayTimeout();
            }
        }

        void TouchUp(object sender, TouchEventArgs e)
        {
            if (Animating)
                return;
            
            this.ItemButtonClick(this, e);
        }

        void TouchMove(object sender, TouchEventArgs e)
        {
            if (Animating) 
                return;

            SelectionState(SelectionStates.Hovered);

            if (ParentMenu != null)
                ParentMenu.HoveredItem(this);

            if (HasItems && !IsMenuOpened)
                IsMenuOpened = true;

            foreach (FrameworkElement item in this.Items)
            {
                SelectionState(item, SelectionStates.Children);
                var menu = item as TouchMenuItem;
                if (menu != null && menu.IsMenuOpened)
                {
                    menu.IsMenuOpened = false;
                }
            }
        }

        void ItemButton_MouseDown(object sender, MouseButtonEventArgs e)
        {
            DelayTimeout();
        }

        private void DelayTimeout()
        {
            if (this.ItemContainer != null)
            {
                this.ItemContainer.DelayTimeout();
            }
        }

        void ItemButton_MouseUp(object sender, MouseButtonEventArgs e)
        {
            if (Animating)
                return;

            this.ItemButtonClick(this, e);
        }

        void ItemButton_MouseMove(object sender, MouseEventArgs e)
        {
            if (Animating) 
                return;

            DelayTimeout();

            SelectionState(SelectionStates.Hovered);

            if (ParentMenu != null)
                ParentMenu.HoveredItem(this);

            if (HasItems && !IsMenuOpened)
                IsMenuOpened = true;

            foreach (FrameworkElement item in this.Items)
            {
                SelectionState(item, SelectionStates.Children);
                var menu = item as TouchMenuItem;
                if (menu != null && menu.IsMenuOpened)
                {
                    menu.IsMenuOpened = false;
                }
            }
        }

        protected void SelectionState(SelectionStates state)
        {
            SelectionState(this, state);
        }

        protected virtual void SelectionState(FrameworkElement elt, SelectionStates state)
        {
            if (ParentMenu is TouchMenuContainer && state == SelectionStates.Children) 
                state = SelectionStates.Active;

            VisualStateManager.GoToState(elt, state.ToString(), false);
        }

        private void HoveredItem(TouchMenuItem hovered)
        {
            this.ParentState();

            foreach (var item in this.Items)
            {
                var menu = item as TouchMenuItem;
                if (menu != null)
                {
                    if (menu != hovered)
                    {
                        SelectionState(menu, SelectionStates.Inactive);
                        if (menu.IsMenuOpened)
                            menu.IsMenuOpened = false;
                    }
                }
            }
        }

        private void ParentState()
        {
            SelectionState(SelectionStates.HoveredParent);

            if (ParentMenu != null)
            {
                foreach (var item in ParentMenu.Items)
                {
                    var menu = item as TouchMenuItem;
                    if (menu != this)
                    {
                        SelectionState(menu, SelectionStates.InactiveParent);
                    }
                }
                ParentMenu.ParentState();
            }
        }

        protected virtual void ItemButtonClick(object sender, RoutedEventArgs e)
        {
            if (ItemContainer != null)
            {
                ItemContainer.DelayTimeout();
                if (ItemContainer.Closing) return;
            }

            if (HasItems)
            {
                if (!IsMenuOpened)
                    IsMenuOpened = true;
            }
            else
            {
                if (Click != null) Click(this, e);
                if (ItemContainer != null)
                    ItemContainer.HideContainer();
            }
        }
        
        internal void PositionMainButton(Rect btn)
        {
            ButtonRect = btn;
            ApplyButtonPosition(ButtonRect);
        }

        internal void PositionMainButton(Point position, Size sz)
        {            
            PositionMainButton(new Rect(position.X, position.Y, sz.Width, sz.Height));
        }

        internal void ApplyButtonPosition(Rect position)
        {
            if (ItemButton != null && position != Rect.Empty)
            {
                Canvas.SetLeft(ItemButton, position.X);
                Canvas.SetTop(ItemButton, position.Y);
                ItemButton.Width = position.Width;
                ItemButton.Height = position.Height;
            }
        }

        #endregion overrides

        
        private void UpdateVisualStates(bool useTransitions)
        {
            if (this.IsMenuOpened)
            {
                VisualStateManager.GoToState(this, "Expanded", useTransitions);
            }
            else
            {
                VisualStateManager.GoToState(this, "Collapsed", useTransitions);
                VisualStateManager.GoToState(this, "Active", false);
            }
            if (this.HasItems)
            {
                VisualStateManager.GoToState(this, "HasItems", useTransitions);
            }
            else
            {
                VisualStateManager.GoToState(this, "NoItems", useTransitions);
            }
        }
        
        internal void CloseMenu()
        {
            SelectionState(SelectionStates.Active);
            if (ItemButton != null)
            {
                ItemButton.Click -= new RoutedEventHandler(ItemButtonClick);
                ItemButton.RemoveHandler(UIElement.MouseMoveEvent, new MouseEventHandler(ItemButton_MouseMove));
                ItemButton.RemoveHandler(UIElement.MouseUpEvent, new MouseButtonEventHandler(ItemButton_MouseUp));
            }
            foreach (var item in Items)
            {
                var menu = item as TouchMenuItem;
                menu.CloseMenu();
            }

            if (IsMenuOpened)
            {
                IsMenuOpened = false;
            }
        }

        internal int GetDepth(int depth=1)
        {
            int maxdepth = depth;
            
            if (Items.Count > 0) 
                maxdepth++;

            foreach (var item in Items)
            {
                var menu = item as TouchMenuItem;
                if (menu != null)
                {
                    int dp = menu.GetDepth(depth);
                    if (dp > maxdepth) 
                        maxdepth = dp;
                }
            }
            return maxdepth;
        }

        public void ResetItems()
        {
            IsMenuOpened = false;
            foreach (var item in Items)
            {
                var menu = item as TouchMenuItem;
                if (menu != null)
                {
                    menu.SelectionState(SelectionStates.Active);
                    menu.ButtonRect = Rect.Empty;
                    menu.ResetItems();
                }
            }
        }

        internal bool WasEvaluated
        {
            get
            {
                return ButtonRect != Rect.Empty;
            }
        }

        public bool Animating { get; set; }
    }
}
